# -*- coding: utf-8 -*-
"""
Created on Thu Sep  4 16:39:36 2025

@author: huangyue
"""

'''
获取则上而下择时指标
'''

# import pymssql
# import pandas as pd
# import numpy as np
from numpy import nan
# import datetime

# import matplotlib.pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
# plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# import sys
# sys.path.append("..")


# # 连接聚源的参数
# server_jydb = "10.10.0.102"
# user_jydb = "jydb"
# password_jydb = "jydb"


# %%
# --- 辅助函数：计算技术指标 ---

def calculate_ema(series, period):
    """计算指数移动平均线 (EMA)"""
    return series.ewm(span=period, adjust=False, min_periods=period).mean()

def calculate_macd(series, fastperiod=12, slowperiod=26, signalperiod=9):
    """
    计算 MACD 指标 (DIF, DEA)
    :param series: pd.Series, 价格序列 (例如收盘价或净值)
    :param fastperiod: int, 快线周期
    :param slowperiod: int, 慢线周期
    :param signalperiod: int, 信号线周期
    :return: tuple (pd.Series, pd.Series), 返回 DIF 和 DEA 序列
    """
    ema_fast = calculate_ema(series, fastperiod)
    ema_slow = calculate_ema(series, slowperiod)
    dif = ema_fast - ema_slow
    dea = calculate_ema(dif, signalperiod)
    # macd_hist = dif - dea # MACD柱状图，这里不需要
    return dif, dea

def calculate_rsi(series, period=14):
    """
    计算相对强弱指数 (RSI) - 使用 Wilder's Smoothing
    :param series: pd.Series, 价格序列
    :param period: int, RSI 周期
    :return: pd.Series, RSI 序列
    """
    delta = series.diff()
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)

    # 使用 Wilder's smoothing (alpha = 1 / period)
    avg_gain = gain.ewm(alpha=1/period, adjust=False, min_periods=period).mean()
    avg_loss = loss.ewm(alpha=1/period, adjust=False, min_periods=period).mean()

    # 防止除以零
    rs = avg_gain / avg_loss.replace(0, nan) # 避免除零，若avg_loss为0，RSI应为100

    rsi = 100 - (100 / (1 + rs))
    rsi = rsi.fillna(100) # 处理 avg_loss 为 0 的情况 (rs为inf)
    # 处理初始NaN值 (可选，取决于是否需要在有足够数据前填充)
    # rsi[:period] = nan

    return rsi




# %% 因子计算

def getFactor(res):
    # --- 基础设置与配置 ---
    print("配置参数...")
    ma_periods_price_above = [5, 30]
    ma_periods_cross = [(30, 60)] # (short, long)
    macd_params = [(12, 26, 9), (8, 17, 6)]
    momentum_periods = [10, 20, 30]
    rsi_params = [(10, 50),(20, 50)] # (period, threshold)
    
    
    # --- 策略信号生成 ---
    print("生成策略信号...")
    signal_columns = {} # 用于存储信号列名和对应的策略描述
    
    # 1. 价格站上均线策略
    # signal_cols = []
    for n in ma_periods_price_above:
        ma_col = f'MA{n}'
        signal_col = f'Signal_PriceAboveMA{n}'
        res[ma_col] = res['nv'].rolling(window=n, min_periods=1).mean()
        # 计算信号
        res[signal_col] = (res['nv'] - res[ma_col])
        res['tmplong'] = ((res[signal_col]>0) & (res['nv'].diff(1)>0)).astype(int)   # 大于均线，并且大于昨天
        res['tmpshort'] = ((res[signal_col]<0) & (res['nv'].diff(1)<0)).astype(int)   # 小于均线，并且小于昨天
        res[signal_col] = res['tmplong'] - res['tmpshort']   
    
        signal_columns[signal_col] = f'Price > MA({n})'
        print(f"  生成信号: {signal_columns[signal_col]}")
    
    # 2. 均线交叉策略
    for short_p, long_p in ma_periods_cross:        
        ma_short_col = f'MA{short_p}'
        ma_long_col = f'MA{long_p}'
        signal_col = f'Signal_MACross_{short_p}_{long_p}'
        # 确保均线已计算或重新计算
        if ma_short_col not in res.columns:
            res[ma_short_col] = res['nv'].rolling(window=short_p, min_periods=1).mean()
        if ma_long_col not in res.columns:
            res[ma_long_col] = res['nv'].rolling(window=long_p, min_periods=1).mean()
        
        # 计算信号
        res['tmplong'] = ((res['nv'] > res[ma_short_col]) & (res[ma_short_col] > res[ma_long_col])).astype(int)   # 最新>短>长
        res['tmpshort'] = ((res['nv'] < res[ma_short_col]) & (res[ma_short_col] < res[ma_long_col])).astype(int)   # 最新<短<长
        res[signal_col] = res['tmplong'] - res['tmpshort']  
        
        signal_columns[signal_col] = f'MA({short_p}) > MA({long_p})'
        print(f"  生成信号: {signal_columns[signal_col]}")
    
    # 3. MACD策略
    for fast, slow, ma in macd_params:
        dif_col = f'DIF_{fast}_{slow}'
        dea_col = f'DEA_{fast}_{slow}_{ma}'
        signal_col = f'Signal_MACD_{fast}_{slow}_{ma}'
        res[dif_col], res[dea_col] = calculate_macd(res['nv'], fast, slow, ma)
    
        # 计算信号
        res['tmplong'] = ((res[dif_col] > res[dea_col]) & (res[dif_col].diff()>0)\
                          & (res[dif_col] > 0)).astype(int)   # 做多
        res['tmpshort'] = ((res[dif_col] < res[dea_col]) & (res[dif_col].diff()<0)\
                           & (res[dif_col] < 0)).astype(int)   # 做空
        res[signal_col] = res['tmplong'] - res['tmpshort']  
        
        signal_columns[signal_col] = f'MACD({fast},{slow},{ma}) Golden Cross'
        print(f"  生成信号: {signal_columns[signal_col]}")
    
    # 4. 价格动量策略
    for n in momentum_periods:
        # break
        momentum_col = f'Momentum_{n}d'
        signal_col = f'Signal_Momentum_{n}d'
        # 计算N日收益率: (Price[t] / Price[t-N]) - 1
        res[momentum_col] = (res['nv'] / res['nv'].shift(n)) - 1
    
        # 计算信号
        res['tmplong'] = ((res[momentum_col] > 0) & (res['ret'] > 0)).astype(int)   # 做多
        res['tmpshort'] = ((res[momentum_col] < 0) & (res['ret'] < 0)).astype(int)   # 做空
        
        res[signal_col] = res['tmplong'] - res['tmpshort']  
        
        
        signal_columns[signal_col] = f'Momentum({n}d) > 0'
        print(f"  生成信号: {signal_columns[signal_col]}")
    
    # 5. RSI策略
    for period, threshold in rsi_params:
        rsi_col = f'RSI_{period}'
        signal_col = f'Signal_RSI_{period}_{threshold}'
        
        res[rsi_col] = calculate_rsi(res['nv'], period)
        # res[signal_col] = res[rsi_col] > threshold
        
        # 计算信号
        res['tmplong'] = (res[rsi_col] > 100 - threshold).astype(int)   # 做多
        res['tmpshort'] = (res[rsi_col] < threshold).astype(int)   # 做空
        
        res[signal_col] = res['tmplong'] - res['tmpshort']  
        
        signal_columns[signal_col] = f'RSI({period}) > {threshold}'
        print(f"  生成信号: {signal_columns[signal_col]}")
    
    print("所有信号生成完毕。")
    return res,signal_columns

def get_signal(res):
    # 计算信号
    res,signal_columns = getFactor(res)
    
    # 信号合并
    res['all_signal'] = res[signal_columns.keys()].sum(axis=1)
    
    # --- 定义整体信号 ---
    base_signal_columns = signal_columns.keys()
    
    # 方案：
    print("生成整体信号...")
    res['Overall_Signal_Long'] = (res[base_signal_columns].sum(axis=1)>=8)
    res['Overall_Signal_Short'] = (res[base_signal_columns].sum(axis=1)<=-8)
    
    # --- 计算仓位建议 ---
    print("计算仓位建议 (True=+1, False=-1)...")
    # 对每行的信号值求和
    res['仓位建议'] = (res[base_signal_columns]).sum(axis=1)
    print("仓位建议计算完成。")
    
    return res

